/* Time_Windows.ipp
 * 
 *  Author          : Alexander J. Yee
 *  Date Created    : 09/17/2014
 *  Last Modified   : 03/07/2016
 * 
 */

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Dependencies
#include <time.h>
#include <Windows.h>
#include "PublicLibs/ConsoleIO/Label.h"
#include "Time_Windows.h"
namespace ymp{
namespace Time{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void CompileOptions(){
    Console::println_labelm("Time", "WinAPI", 'G');
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
YM_NO_INLINE WallClock WallClock::now(){
//    static int c = 0;
//    cout << "clock: " << c++ << endl;
    LARGE_INTEGER x;
    if (!QueryPerformanceCounter(&x)){
        Console::warning("Unable to access performance counter.");
        Console::quit_program(1);
    }
    WallClock out;
    out.m_ticks = x.QuadPart;
    return out;
}
YM_NO_INLINE double WallClock::operator-(const WallClock& x) const{
    LARGE_INTEGER freqency;
    if (!QueryPerformanceFrequency(&freqency)){
        Console::warning("Unable to access performance counter.");
        Console::quit_program(1);
    }
    return (double)(m_ticks - x.m_ticks) / freqency.QuadPart;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
PerformanceTimeStamp PerformanceTimeStamp::now(){
    PerformanceTimeStamp out;
    out.wall_clock = WallClock::now();

    FILETIME a, b, c, d;
    if (GetProcessTimes(GetCurrentProcess(), &a, &b, &c, &d) == 0){
        Console::warning("Unable to get CPU Clock.");
        Console::quit_program(1);
    }

    out.kernel_clock_ticks = c.dwLowDateTime | ((u64_t)c.dwHighDateTime << 32);
    out.user_clock_ticks   = d.dwLowDateTime | ((u64_t)d.dwHighDateTime << 32);

//    cout << out.user_clock_ticks << endl;

    return out;
}
void PerformanceTimeDuration::reset(){
    wall_time = 0;
    user_time = 0;
    kernel_time = 0;
}
PerformanceTimeDuration PerformanceTimeDuration::time_since(const PerformanceTimeStamp& timestamp){
    return PerformanceTimeStamp::now() - timestamp;
}
void PerformanceTimeDuration::operator+=(const PerformanceTimeDuration& duration){
    wall_time += duration.wall_time;
    user_time += duration.user_time;
    kernel_time += duration.kernel_time;
}
PerformanceTimeDuration operator-(const PerformanceTimeStamp& end, const PerformanceTimeStamp& start){
    PerformanceTimeDuration out;
    out.wall_time = end.wall_clock - start.wall_clock;
    out.user_time = (end.user_clock_ticks - start.user_clock_ticks) * 0.0000001;
    out.kernel_time = (end.kernel_clock_ticks - start.kernel_clock_ticks) * 0.0000001;
    return out;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
YM_NO_INLINE std::string tostr_now(){
    struct tm newtime;
    time_t aclock;

    time(&aclock);
    localtime_s(&newtime, &aclock);

    char buffer[32];
    asctime_s(buffer, 32, &newtime);

    //  Stop at the first control character.
    upL_t c = 0;
    while (buffer[c] >= 32){
        c++;
    }
    buffer[c] = '\0';

    return buffer;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
}
}
